/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date: 2010-03-24 23:21:26 +0800 (周三, 24 三月 2010) $
Version:   $Revision: 21881 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/


#include "WxObjectOrientationMarkerMapper3D.h"
#include "mitkDataNode.h"
#include "mitkProperties.h"
#include "mitkColorProperty.h"
#include "mitkVtkPropRenderer.h"

#include <vtkActor.h>
#include <vtkAppendPolyData.h>
#include <vtkPropAssembly.h>
#include <vtkRenderer.h>
#include <vtkProperty.h>
#include <vtkPolyDataMapper.h>
#include <vtkCellArray.h>
#include <vtkVectorText.h>
#include <vtkTransform.h>
#include <vtkMatrix4x4.h>
#include <vtkArrowSource.h>

#if (VTK_MAJOR_VERSION >= 5)
#include <vtkPolyDataAlgorithm.h>
#else
#include <vtkPolyData.h>
#endif

#include <stdlib.h>

const mitk::WxObjectOrientationMarker* mitk::WxObjectOrientationMarkerMapper3D::GetInput()
{
    return static_cast<const mitk::WxObjectOrientationMarker * > ( GetData() );
}

mitk::WxObjectOrientationMarkerMapper3D::WxObjectOrientationMarkerMapper3D() :
m_LineWidth(5), m_LineLength(40),m_NeedUpdate(true)
{
  m_PointsAssembly = vtkPropAssembly::New();
  m_ArrowXActor = vtkActor::New();
  m_ArrowYActor = vtkActor::New();
  m_ArrowZActor = vtkActor::New();
  m_ArrowXMapper=vtkPolyDataMapper::New();
  m_ArrowYMapper=vtkPolyDataMapper::New();
  m_ArrowZMapper=vtkPolyDataMapper::New();
}

mitk::WxObjectOrientationMarkerMapper3D::~WxObjectOrientationMarkerMapper3D()
{
    m_PointsAssembly->Delete();
    m_ArrowXActor->Delete();
    m_ArrowYActor->Delete();
    m_ArrowZActor->Delete();
    m_ArrowXMapper->Delete();
    m_ArrowYMapper->Delete();
    m_ArrowZMapper->Delete();

}

void mitk::WxObjectOrientationMarkerMapper3D::ReleaseGraphicsResources(vtkWindow *renWin)
{
  m_PointsAssembly->ReleaseGraphicsResources(renWin);
  m_ArrowXActor->ReleaseGraphicsResources(renWin);
  m_ArrowYActor->ReleaseGraphicsResources(renWin);
  m_ArrowZActor->ReleaseGraphicsResources(renWin);
}



void mitk::WxObjectOrientationMarkerMapper3D::GenerateData( mitk::BaseRenderer *renderer )
{
    if(m_NeedUpdate)
    {
        SetDefaultProperties(this->GetDataNode());
        m_NeedUpdate=false;

        vtkArrowSource* arrowSource=vtkArrowSource::New();
        arrowSource->SetShaftResolution(50);
        arrowSource->SetTipResolution(40);
        m_ArrowXMapper->SetInputConnection( arrowSource->GetOutputPort());
        m_ArrowXActor->SetMapper(m_ArrowXMapper);
        arrowSource->Delete();
        m_PointsAssembly->AddPart(m_ArrowXActor);

        arrowSource=vtkArrowSource::New();
        arrowSource->SetShaftResolution(50);
        arrowSource->SetTipResolution(40);
        m_ArrowYMapper->SetInputConnection( arrowSource->GetOutputPort());
        m_ArrowYActor->SetMapper(m_ArrowYMapper);
        arrowSource->Delete();
        m_PointsAssembly->AddPart(m_ArrowYActor);

        arrowSource=vtkArrowSource::New();
        arrowSource->SetShaftResolution(50);
        arrowSource->SetTipResolution(40);
        m_ArrowZMapper->SetInputConnection( arrowSource->GetOutputPort());
        m_ArrowZActor->SetMapper(m_ArrowZMapper);
        arrowSource->Delete();
        m_PointsAssembly->AddPart(m_ArrowZActor);
        m_PointsAssembly->VisibilityOn();
    }
    ApplyProperties(NULL,renderer);

}


void mitk::WxObjectOrientationMarkerMapper3D::ResetMapper( BaseRenderer* /*renderer*/ )
{
  m_PointsAssembly->VisibilityOff();
}


vtkProp* mitk::WxObjectOrientationMarkerMapper3D::GetVtkProp(mitk::BaseRenderer * /*renderer*/)
{
  return m_PointsAssembly;
}

void mitk::WxObjectOrientationMarkerMapper3D::UpdateVtkTransform(mitk::BaseRenderer * /*renderer*/)
{
    mitk::Geometry3D* g3d=this->GetDataNode()->GetData()->GetGeometry();
    vtkMatrix4x4 *m=vtkMatrix4x4::New();
    m->Identity();

    mitk::Vector3D vx=g3d->GetAxisVector(0); /*MITK_INFO<<vx.GetNorm();*/ vx.Normalize();
    mitk::Vector3D vy=g3d->GetAxisVector(1); /*MITK_INFO<<vy.GetNorm();*/ vy.Normalize();
    mitk::Vector3D vz=g3d->GetAxisVector(2); /*MITK_INFO<<vz.GetNorm();*/ vz.Normalize();

    int i,j;
    for(i=0;i<3;++i)
        m->SetElement(i, 0, vx[i]);
    for(i=0;i<3;++i)
        m->SetElement(i, 1, vy[i]);
    for(i=0;i<3;++i)
        m->SetElement(i, 2, vz[i]);

    for(i=0;i<3;++i)
      m->SetElement(i, 3, g3d->GetIndexToWorldTransform()->GetOffset()[i]);
    m->Modified();

    vtkTransform* vtktransform=vtkTransform::New();
    vtktransform->SetMatrix(m);
    vtkTransform* transformX=vtkTransform::New();
    transformX->DeepCopy(vtktransform);
    transformX->Scale(m_LineLength,m_LineWidth,m_LineWidth);

    vtkTransform* transformY=vtkTransform::New();
    transformY->DeepCopy(vtktransform);
    transformY->RotateZ(90);
    transformY->RotateX(90);
    transformY->Scale(m_LineLength,m_LineWidth,m_LineWidth);

    vtkTransform* transformZ=vtkTransform::New();
    transformZ->DeepCopy(vtktransform);
    transformZ->RotateY(-90);
    transformZ->RotateX(-90);
    transformZ->Scale(m_LineLength,m_LineWidth,m_LineWidth);

    //  MITK_INFO<<"XXXXXXXXXXXXXXXXX";
    //  m=transformX->GetMatrix();
    //  MITK_INFO<<m->Element[0][0]<<" "<<m->Element[0][1]<<" "<< m->Element[0][2];
    //  MITK_INFO<<m->Element[1][0]<<" "<<m->Element[1][1]<<" "<< m->Element[1][2];
    //  MITK_INFO<<m->Element[2][0]<<" "<<m->Element[2][1]<<" "<< m->Element[2][2];

    //  MITK_INFO<<"ITK";

    //  MITK_INFO<<mat[0][0]<<" "<<mat[0][1]<<" "<< mat[0][2];
    //  MITK_INFO<<mat[1][0]<<" "<<mat[1][1]<<" "<< mat[1][2];
    //  MITK_INFO<<mat[2][0]<<" "<<mat[2][1]<<" "<< mat[2][2];

    m_ArrowXActor->SetUserTransform(transformX);
    m_ArrowYActor->SetUserTransform(transformY);
    m_ArrowZActor->SetUserTransform(transformZ);

    transformX->Delete();
    transformY->Delete();
    transformZ->Delete();
    m->Delete();
}

void mitk::WxObjectOrientationMarkerMapper3D::ApplyProperties(vtkActor* /*actor*/, mitk::BaseRenderer* renderer)
{
   // Superclass::ApplyProperties( NULL, renderer ) ;

    mitk::Color coordinateXDiaplayColor;coordinateXDiaplayColor.Set(1,0,0);
    mitk::Color coordinateYDiaplayColor;coordinateYDiaplayColor.Set(0,1,0);
    mitk::Color coordinateZDiaplayColor;coordinateZDiaplayColor.Set(0,0,1);
    if (dynamic_cast<mitk::FloatProperty *>(this->GetDataNode()->GetProperty("CoordinateDiaplayWidth")) != NULL)
        m_LineWidth = dynamic_cast<mitk::FloatProperty*>(this->GetDataNode()->GetProperty("CoordinateDiaplayWidth"))->GetValue();
    if (dynamic_cast<mitk::FloatProperty *>(this->GetDataNode()->GetProperty("CoordinateDiaplayLength")) != NULL)
        m_LineLength = dynamic_cast<mitk::FloatProperty*>(this->GetDataNode()->GetProperty("CoordinateDiaplayLength"))->GetValue();

    if (dynamic_cast<mitk::ColorProperty *>(this->GetDataNode()->GetProperty("CoordinateXDiaplayColor")) != NULL)
    {
        coordinateXDiaplayColor = dynamic_cast<mitk::ColorProperty*>(this->GetDataNode()->GetProperty("CoordinateXDiaplayColor"))->GetColor();
       // MITK_INFO<<coordinateXDiaplayColor[0]<<"  "<<coordinateXDiaplayColor[1]<<" "<<coordinateXDiaplayColor[2];
    }
    if (dynamic_cast<mitk::ColorProperty *>(this->GetDataNode()->GetProperty("CoordinateYDiaplayColor")) != NULL)
    {
        coordinateYDiaplayColor = dynamic_cast<mitk::ColorProperty*>(this->GetDataNode()->GetProperty("CoordinateYDiaplayColor"))->GetColor();
       // MITK_INFO<<coordinateYDiaplayColor[0]<<"  "<<coordinateYDiaplayColor[1]<<" "<<coordinateYDiaplayColor[2];
    }
    if (dynamic_cast<mitk::ColorProperty *>(this->GetDataNode()->GetProperty("CoordinateZDiaplayColor")) != NULL)
    {
        coordinateZDiaplayColor = dynamic_cast<mitk::ColorProperty*>(this->GetDataNode()->GetProperty("CoordinateZDiaplayColor"))->GetColor();
       // MITK_INFO<<coordinateZDiaplayColor[0]<<"  "<<coordinateZDiaplayColor[1]<<" "<<coordinateZDiaplayColor[2];
    }




    m_ArrowXActor->GetProperty()->SetColor(coordinateXDiaplayColor[0],coordinateXDiaplayColor[1],coordinateXDiaplayColor[2]);
    m_ArrowYActor->GetProperty()->SetColor(coordinateYDiaplayColor[0],coordinateYDiaplayColor[1],coordinateYDiaplayColor[2]);
    m_ArrowZActor->GetProperty()->SetColor(coordinateZDiaplayColor[0],coordinateZDiaplayColor[1],coordinateZDiaplayColor[2]);

}



void mitk::WxObjectOrientationMarkerMapper3D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite)
{


    if(node->GetData()==NULL) return;
    mitk::Geometry3D *g3d=node->GetData()->GetGeometry();

    mitk::Vector3D AxisX=g3d->GetAxisVector(0);
    mitk::Vector3D AxisY=g3d->GetAxisVector(1);
    mitk::Vector3D AxisZ=g3d->GetAxisVector(2);

    float lineLength=(AxisX.GetNorm()+AxisY.GetNorm()+AxisZ.GetNorm())*0.3333;
    float lineWidth=lineLength*0.5;


    node->SetProperty( "CoordinateDiaplayWidth", mitk::FloatProperty::New(lineWidth), renderer );
    node->SetProperty( "CoordinateDiaplayLength", mitk::FloatProperty::New(lineLength), renderer );
    node->SetProperty( "CoordinateXDiaplayColor", mitk::ColorProperty::New(1.0f,0.0f,0.0f), renderer );
    node->SetProperty( "CoordinateYDiaplayColor", mitk::ColorProperty::New(0.0f,1.0f,0.0f), renderer );
    node->SetProperty( "CoordinateZDiaplayColor", mitk::ColorProperty::New(0.0f,0.0f,1.0f), renderer );

    Superclass::SetDefaultProperties(node, renderer, overwrite);
}

